package org.javaforever.oville.operator;

import java.util.ArrayList;
import java.util.List;

import org.javaforever.oville.TextWord;
import org.javaforever.oville.ValidateException;
import org.javaforever.oville.Word;

public class QOps {
	public static Word qZip(Word val1,Word val2) throws ValidateException{
		StringBuilder val1Str = new StringBuilder(val1.toQuadStr());
		StringBuilder val2Str = new StringBuilder(val2.toQuadStr());
		StringBuilder result = new StringBuilder();
		for (int i=0;i<32;i++) {
			char r = qBitZip(val1Str.charAt(i),val2Str.charAt(i));
			result.append(r);
		}
		System.out.println("JerryDebug:qAnd:"+result.toString());
		return Word.fromQuadStr(result.toString());
	}
	
	public static Word qZipAll(List<Word> wordList) throws ValidateException{
		if (wordList.size() == 0) {
			throw new ValidateException("WordList is empty.");
		} else if (wordList.size()==1) {
			return wordList.get(0);
		}else {
			Word target = wordList.get(0);
			for (int i=1;i<wordList.size();i++) {
				target = qZip(target,wordList.get(i));
				if (isAllQ(target)) return target;
			}
			return target;
		}
	}
	
	private static boolean isAllQ(Word word) throws ValidateException {
		TextWord tw = TextWord.fromStr(word.toQuadStr());
		for (char ch: tw.getTextWord()) {
			if (ch != 'Q') return false;
		}
		return true;
	}

	public static List<Word> qAnd(Word val1,Word val2) throws ValidateException{
		StringBuilder val1Str = new StringBuilder(val1.toQuadStr());
		StringBuilder val2Str = new StringBuilder(val2.toQuadStr());
		StringBuilder result = new StringBuilder();
		for (int i=0;i<32;i++) {
			char r = qBitAnd(val1Str.charAt(i),val2Str.charAt(i));
			result.append(r);
		}
		System.out.println("JerryDebug:qAnd:"+result.toString());
		return parseSChars(result.toString());
	}
	
	public static List<Word> qOr(Word val1,Word val2) throws ValidateException{
		StringBuilder val1Str = new StringBuilder(val1.toQuadStr());
		StringBuilder val2Str = new StringBuilder(val2.toQuadStr());
		StringBuilder result = new StringBuilder();
		for (int i=0;i<32;i++) {
			char r = qBitOr(val1Str.charAt(i),val2Str.charAt(i));
			result.append(r);
		}
		System.out.println("JerryDebug:qOr:"+result.toString());
		return parseSChars(result.toString());
	}
	
	public static List<Word> qXor(Word val1,Word val2) throws ValidateException{
		StringBuilder val1Str = new StringBuilder(val1.toQuadStr());
		StringBuilder val2Str = new StringBuilder(val2.toQuadStr());
		StringBuilder result = new StringBuilder();
		for (int i=0;i<32;i++) {
			char r = qBitXor(val1Str.charAt(i),val2Str.charAt(i));
			result.append(r);
		}
		System.out.println("JerryDebug:qXor:"+result.toString());
		return parseSChars(result.toString());
	}
	
	public static Word qNot(Word val1) throws ValidateException{
		StringBuilder val1Str = new StringBuilder(val1.toQuadStr());
		StringBuilder result = new StringBuilder();
		for (int i=0;i<32;i++) {
			char r = qBitNot(val1Str.charAt(i));
			result.append(r);
		}
		System.out.println("JerryDebug:qNot:"+result.toString());
		return Word.fromQuadStr(result.toString());
	}
	
	public static List<Word> qBitAdd(Word val1,Word val2) throws ValidateException{
		StringBuilder val1Str = new StringBuilder(val1.toQuadStr());
		StringBuilder val2Str = new StringBuilder(val2.toQuadStr());
		StringBuilder result = new StringBuilder();
		for (int i=0;i<32;i++) {
			char r = qBitAnd(val1Str.charAt(i),val2Str.charAt(i));
			result.append(r);
		}
		System.out.println("JerryDebug:qAnd:"+result.toString());
		return parseSChars(result.toString());
	}
	
	public static List<Word> qAdd(Word val1,Word val2) throws ValidateException{
		StringBuilder val1Str = new StringBuilder(val1.toQuadStr());
		StringBuilder val2Str = new StringBuilder(val2.toQuadStr());
		StringBuilder result = new StringBuilder();
		for (int i=0;i<32;i++) {
			char r = qBitAnd(val1Str.charAt(i),val2Str.charAt(i));
			result.append(r);
		}
		System.out.println("JerryDebug:qAnd:"+result.toString());
		return parseSChars(result.toString());
	}
	
	public static char qBitAnd(char val1,char val2) throws ValidateException{
		if (val1=='0'&& val2=='0') return '0';
		else if (val1=='0'&& val2=='1') return '0';
		else if (val1=='0'&& val2=='Q') return '0';
		else if (val1=='0'&& val2=='P') return '0';
		else if (val1=='1'&& val2=='0') return '0';
		else if (val1=='1'&& val2=='1') return '1';
		else if (val1=='1'&& val2=='Q') return 'Q';
		else if (val1=='Q'&& val2=='0') return '0';
		else if (val1=='Q'&& val2=='1') return 'Q';
		else if (val1=='Q'&& val2=='Q') return 'Q';
		else if (val1=='Q'&& val2=='P') return 'S';
		else if (val1=='P'&& val2=='0') return '0';
		else if (val1=='P'&& val2=='1') return '1';
		else if (val1=='P'&& val2=='Q') return 'S';
		else if (val1=='P'&& val2=='P') return 'P';
		else return ' ';
	}
	
	public static char qBitZip(char val1,char val2) throws ValidateException{
		if (val1=='0'&& val2=='0') return '0';
		else if (val1=='0'&& val2=='1') return 'Q';
		else if (val1=='0'&& val2=='Q') return 'Q';
		else if (val1=='0'&& val2=='P') return '0';
		else if (val1=='1'&& val2=='0') return 'Q';
		else if (val1=='1'&& val2=='1') return '1';
		else if (val1=='1'&& val2=='Q') return 'Q';
		else if (val1=='Q'&& val2=='0') return 'Q';
		else if (val1=='Q'&& val2=='1') return 'Q';
		else if (val1=='Q'&& val2=='Q') return 'Q';
		else if (val1=='Q'&& val2=='P') return 'Q';
		else if (val1=='P'&& val2=='0') return '0';
		else if (val1=='P'&& val2=='1') return '1';
		else if (val1=='P'&& val2=='Q') return 'Q';
		else if (val1=='P'&& val2=='P') return 'P';
		else return ' ';
	}
	
	/*
	 * J为进位 10
	 * K为进位 QQ
	 * S为分裂 (0)(1)
	 * L为分裂 (10)(01)
	 */
	public static char qBitOr(char val1,char val2) throws ValidateException{
		if (val1=='0'&& val2=='0') return '0';
		else if (val1=='0'&& val2=='1') return '1';
		else if (val1=='0'&& val2=='Q') return 'Q';
		else if (val1=='0'&& val2=='P') return '0';
		else if (val1=='1'&& val2=='0') return '1';
		else if (val1=='1'&& val2=='1') return '1';
		else if (val1=='1'&& val2=='Q') return '1';
		else if (val1=='Q'&& val2=='0') return 'Q';
		else if (val1=='Q'&& val2=='1') return '1';
		else if (val1=='Q'&& val2=='Q') return 'Q';
		else if (val1=='Q'&& val2=='P') return 'S';
		else if (val1=='P'&& val2=='0') return '0';
		else if (val1=='P'&& val2=='1') return '1';
		else if (val1=='P'&& val2=='Q') return 'S';
		else if (val1=='P'&& val2=='P') return 'P';
		else return ' ';
	}
	
	/*
	 * J为进位 10
	 * K为进位 QQ
	 * S为分裂 (0)(1)
	 * L为分裂 (10)(01)
	 */
	public static char qBitXor(char val1,char val2) throws ValidateException{
		if (val1=='0'&& val2=='0') return '0';
		else if (val1=='0'&& val2=='1') return '1';
		else if (val1=='0'&& val2=='Q') return 'Q';
		else if (val1=='0'&& val2=='P') return '0';
		else if (val1=='1'&& val2=='0') return '1';
		else if (val1=='1'&& val2=='1') return '0';
		else if (val1=='1'&& val2=='Q') return 'Q';
		else if (val1=='Q'&& val2=='0') return 'Q';
		else if (val1=='Q'&& val2=='1') return 'Q';
		else if (val1=='Q'&& val2=='Q') return 'Q';
		else if (val1=='Q'&& val2=='P') return 'S';
		else if (val1=='P'&& val2=='0') return '0';
		else if (val1=='P'&& val2=='1') return '1';
		else if (val1=='P'&& val2=='Q') return 'S';
		else if (val1=='P'&& val2=='P') return 'P';
		else return ' ';
	}
	
	public static char qBitNot(char val1) throws ValidateException{
		if (val1=='0') return '1';
		else if (val1=='1') return '0';
		else if (val1=='Q') return 'Q';
		else if (val1=='P') return 'P';
		return ' ';
	}
	
	/*
	 * J为进位 10
	 * K为进位 QQ
	 * S为分裂 (0)(1)
	 * L为分裂 (10)(01)
	 */
	public static char qBitAdd(char val1,char val2) throws ValidateException{
		if (val1=='0'&& val2=='0') return '0';
		else if (val1=='0'&& val2=='1') return '1';
		else if (val1=='0'&& val2=='Q') return 'Q';
		else if (val1=='0'&& val2=='P') return '0';
		else if (val1=='1'&& val2=='0') return '1';
		else if (val1=='1'&& val2=='1') return 'J';
		else if (val1=='1'&& val2=='Q') return 'L';
		else if (val1=='Q'&& val2=='0') return 'Q';
		else if (val1=='Q'&& val2=='1') return 'L';
		else if (val1=='Q'&& val2=='Q') return 'K';
		else if (val1=='Q'&& val2=='P') return 'S';
		else if (val1=='P'&& val2=='0') return '0';
		else if (val1=='P'&& val2=='1') return '1';
		else if (val1=='P'&& val2=='Q') return 'S';
		else if (val1=='P'&& val2=='P') return 'P';
		else return ' ';
	}
	
	public static List<Word> parseSChars(String wqs) throws ValidateException{
		List<String> results = new ArrayList<>();
		long sCounts = countS(wqs);
		System.out.println("JerryDebug:"+sCounts+":"+Math.pow(sCounts, 2));
		long ceiling = (long) (Math.round(Math.pow(2, sCounts))- 0.1);
		for (long i=0;i<=ceiling;i++) {
			results.add(wqs);
		}
		List<Word> finalresults = new ArrayList<>();
		for (int i=0;i<results.size();i++) {
			finalresults.add(replaceSesWithVals(results.get(i),i));
		}
		return finalresults;
	}
	
	private static Word replaceSesWithVals(String targetStr, long vals) throws ValidateException {		
		int sCounts = countS(targetStr);		
		StringBuilder targetSb = new StringBuilder(targetStr);
		String valsStr = longValsToString(vals,sCounts);
		System.out.println("JerryDebug:"+targetStr+":"+vals+":"+sCounts+":"+valsStr);
		if (sCounts>0&&sCounts != valsStr.length()) throw new ValidateException("Unmatch Ses and vals");
		int qpos =0;
		for (int i=0;i<sCounts;i++) {
			for (int j=0;j<targetSb.length();j++) {
				if ('S'== targetSb.charAt(j)) {
					targetSb.replace(j, j+1, ""+valsStr.charAt(qpos));
					qpos++;
				}
			}			
		}
		//System.out.println("JerryDebug:"+Word.fromQuadStr(targetSb.toString()));
		return Word.fromQuadStr(targetSb.toString());
	}
	
	private static String longValsToString(long vals, int sCounts) throws ValidateException {
		String retVals = Long.toBinaryString(vals);
		if (sCounts>0&&retVals.length()>sCounts) throw new ValidateException("Unmatch Qs and vals");
		else if (retVals.length()<sCounts) {
			int ceiling = sCounts - retVals.length();
			for (int i=0;i< ceiling;i++) {
				retVals = "0" + retVals;
			}		
		}
		return retVals;
	}
	
	private static int countS(String wordStr) throws ValidateException{
		int count = 0;
		for (int i=0;i<wordStr.length();i++) {
			if ('S' == wordStr.charAt(i)) {
				count ++;
			}
		}
		return count;
	}
	
	public static void main(String [] args) throws Exception{
		Word w1 = Word.fromQuadStr("Q00000000000000000000000000P000P");
		Word w2 = Word.fromQuadStr("P00000000000000000000000000P000Q");
		List<Word> result = qAnd(w1,w2);
		System.out.println("JerryDebug:Result:");
		for (Word w:result) {
			System.out.println(w.toQuadStr());
		}
		
		List<Word> resultOr = qOr(w1,w2);
		System.out.println("JerryDebug:Result:QOr:");
		for (Word w:resultOr) {
			System.out.println(w.toQuadStr());
		}
	}
}
